home *** CD-ROM | disk | FTP | other *** search
/ Turnbull China Bikeride / Turnbull China Bikeride - Disc 2.iso / STUTTGART / UNIXTOOL / MEMACS / C / Tags < prev    next >
Text File  |  1990-06-26  |  13KB  |  532 lines

  1. /*
  2.  * The routines in this file provides support for  vi-like tagging
  3.  * of defined identifiers.  We presuppose the "tags" file in the
  4.  * current directory (constructed by 'ctags' or 'etags'), with each
  5.  * entry on the following format:
  6.  *
  7.  *     identifier<tab>file<tab>vi-search-pattern
  8.  *
  9.  * Code will be generated if both  MAGIC and CTAGS  is wanted.
  10.  *                            880826mhs
  11.  * 890622mhs
  12.  * Changed code so as to take advantage of the new FAST search routine
  13.  * i.e. we do not use the MAGIC search.
  14.  * Also implemented indexing of the "tags" file to reduce the time used
  15.  * when tagging is performed more than once.  Moreover, we now support
  16.  * tagging of file(s) other than those in the current directory.  We
  17.  * automatically locates the correct "tags" and records its vital info
  18.  * (only the first time it's referenced!!).
  19.  * 890627mhs
  20.  * Added possibility to be prompted for word to tag.  You will be prompted
  21.  * if you execute the tag-word function whenever dot is not within a word.
  22.  */
  23.  
  24. #include <stdio.h>
  25. #include "estruct.h"
  26.  
  27. #if CTAGS
  28. #include "eproto.h"
  29. #include "edef.h"
  30. #include "elang.h"
  31.  
  32. static char SVER[] = "@(#) %M% %I% %H%";
  33.  
  34. #define min(x, y)    ((x) <= (y) ? (x) : (y))
  35.  
  36. #define INDEX(c)    (islower(c) ? c-'a'+27 : \
  37.              (isletter(c) ? c-'A'+1: ((c == '_') ? 0 : -1)))
  38. #define NINDEXES    26+26+1
  39. #define TAGWIDTH    30
  40.  
  41. typedef struct    TAG {
  42.     struct    TAG *t_tagp;        /* Link to the next 'tags' file    */
  43.     char    t_path[NFILEN];        /* Path of 'tags' file        */
  44.     FILE    *t_fp;            /* File pointer to 'tags' file    */
  45.     char    t_wd[TAGWIDTH+1];    /* Word last tagged (this file)    */
  46.     char    t_fname[NFILEN];    /* Holds name of file from where*/
  47.                     /* we tagged.            */
  48.     int    t_indexed;        /* Flag:  1=file is indexed    */
  49.     long    t_dotos[NINDEXES];    /* Offsets of first chars (used    */
  50.                     /* for speed-up purposes only).    */
  51. }    TAG;
  52.  
  53. static TAG *theadp = NULL;        /* Pointer to the head of the    */
  54.                     /* 'tags'-chain.        */
  55. static TAG *curtp  = NULL;        /* Currently in-use 'tags'.    */
  56.  
  57.  
  58. /*
  59.  * Look-up a 'tags' file in the directory given by
  60.  * 'path'.  If such a file exists and we are allowed
  61.  * to read it, we'll read it and construct an index
  62.  * of file positions of the first occurence of each
  63.  * starting character ('_', 'a'-'z', 'A'-'Z').  We
  64.  * return with TRUE only if we are succesfull.
  65.  */
  66.  
  67. newtags(path)
  68. char path[NFILEN];
  69. {
  70.     register TAG    *tnewp;
  71.     register int    i = NINDEXES;
  72.  
  73.     if ((tnewp = (TAG *)malloc(sizeof(TAG))) == NULL) {
  74.         mlwrite("[OUT OF MEMORY]");
  75.         return(FALSE);
  76.     }
  77.     strcpy(tnewp->t_path, path);
  78.     strcat(path, "tags");
  79.     if ((tnewp->t_fp = fopen(path, "r")) == NULL) {
  80.         free((char *)tnewp);
  81.         return(FALSE);
  82.     }
  83.  
  84.     tnewp->t_tagp  = theadp;
  85.     curtp = theadp = tnewp;
  86.     strcpy(tnewp->t_fname, curbp->b_fname);
  87.     strcpy(tnewp->t_wd, "");
  88.  
  89.     /* Initialize index...    */
  90.     tnewp->t_indexed = FALSE;
  91.     while (i > 0)
  92.         tnewp->t_dotos[--i] = -1L;
  93.  
  94.     return(TRUE);
  95. }
  96.  
  97.  
  98. /*
  99.  * Look-up 'tags' file; first in our list and if it isn't there
  100.  * try it the hard way.  If we find the file we return TRUE.
  101.  */
  102.  
  103. lookup()
  104. {
  105.     TAG        *tmp = curtp;    /* Remember current 'tags'    */
  106.     char        cpath[NFILEN];    /* Path of current file        */
  107.     register char    *cp;        /* Auxiliary pointer        */
  108.     register int    nope = TRUE;    /* True if 'tags' is unknown    */
  109.     char        *fn;        /* Current buffer file name    */
  110.  
  111.     fn = curbp->b_fname;
  112.  
  113.     cp = fn + strlen(fn) - 1;
  114.  
  115. #if    RISCOS
  116.     while (cp >= fn && *cp != DIRSEPCHAR && *cp != ':')
  117.         cp--;
  118.  
  119.     /* We assume that files in directory C, H, L or Y are tagged in
  120.      * the current directory. Others are tagged where they stand.
  121.      */
  122.     if (cp >= fn + 1 && *cp == DIRSEPCHAR)
  123.     {
  124.         switch (upperc(cp[-1]))
  125.         {
  126.         case 'C':
  127.         case 'H':
  128.         case 'L':
  129.         case 'Y':
  130.             if (cp == fn + 1 || cp[-2] == DIRSEPCHAR)
  131.                 cp -= 2;
  132.         }
  133.     }
  134.  
  135. #else
  136. #if    MSDOS
  137.     while (cp >= curbp->b_fname  &&  *cp != DIRSEPCHAR  &&  *cp != ':')
  138. #else
  139.     while (cp >= curbp->b_fname  &&  *cp != DIRSEPCHAR)
  140. #endif
  141.         cp--;
  142. #endif
  143.  
  144.     memset(cpath, '\0', NFILEN);
  145.     if (cp >= curbp->b_fname)
  146.         strncpy(cpath, curbp->b_fname, (int)(cp - curbp->b_fname) + 1);
  147.     else
  148.         strcpy(cpath, CURDIR);
  149.  
  150.     while (curtp != NULL  &&  (nope = strcmp(curtp->t_path, cpath)) != 0)
  151.         curtp = curtp->t_tagp;
  152.  
  153.     if (nope == 0)            /* We already knew the tags path*/
  154.         return(TRUE);
  155.  
  156.     /* We'll have to look it up...    */
  157.     if (newtags(cpath))
  158.         return(TRUE);
  159.     else
  160.         curtp = tmp;
  161.     return(FALSE);
  162. }
  163.  
  164.  
  165. /*
  166.  * Create an index of offsets into the 'tags' file at
  167.  * curtp->t_path.  We use the first character of the
  168.  * tagged words as our index index.
  169.  */
  170.  
  171. fix_index()
  172. {
  173.     register int    i  = -1;
  174.     register long    lastpos = 0L;
  175.     char        line[NLINE];
  176.  
  177.     if (curtp->t_indexed == TRUE)
  178.         return;
  179.  
  180.     mlwrite("[Indexing 'tags' file, please wait...]");
  181.  
  182.     while (fgets(line, NLINE, curtp->t_fp) != NULL) {
  183.         if (i != INDEX(line[0])  &&  (i=INDEX(line[0])) != -1)
  184.             curtp->t_dotos[i] = lastpos;
  185.         lastpos = (long)ftell(curtp->t_fp);
  186.     }
  187.     curtp->t_indexed = TRUE;
  188. }
  189.  
  190.  
  191. /*
  192.  * Put the rest of the characters of the current word at '.' in
  193.  * str (but maximum lmax characters).  '.' is preserved.
  194.  */
  195. restword(str, lmax)
  196. char *str;
  197. int  lmax;
  198. {
  199.     register int i;
  200.     register int go_on  = TRUE;
  201.     register LINE *dotp = curwp->w_dotp;    /* Preserve '.' info    */
  202.     register int   doto = curwp->w_doto;    /* Preserve '.' info    */
  203.  
  204.     for (i=0 ; go_on  &&  i < lmax-1  &&  inword() ; i++) {
  205.         str[i] = lgetc(curwp->w_dotp, curwp->w_doto);
  206.         go_on  = forwchar(FALSE, 1);
  207.     }
  208.  
  209.     str[i] = 0;            /* Terminate word        */
  210.     curwp->w_dotp = dotp;        /* Restore '.'             */
  211.     curwp->w_doto = doto;
  212.  
  213.     return(TRUE);
  214. }
  215.  
  216.  
  217. /*
  218.  * Move '.' backwards until start of current word.
  219.  * NOTE, we rely on inword(), which normally don't
  220.  * consider '_' part of a word.  You might want to
  221.  * change inword() in order to obtain satisfactory
  222.  * results from this code (I did).
  223.  */
  224.  
  225. backupword(f, n)
  226.  
  227. int f, n;
  228.  
  229. {
  230.     while (inword())
  231.         if (backchar(FALSE, 1) == FALSE)
  232.             break;
  233.     if (!inword())        /* Adjust for not beginning of file    */
  234.         forwchar(FALSE, 1);
  235.  
  236.     return(TRUE);
  237. }
  238.  
  239.  
  240. /*
  241.  * Alter the vi-search-pattern in pattern inorder to use it
  242.  * as a search pattern for uEMACS' search routines.
  243.  * The vi-pattern contains \-escaped characters...we have
  244.  * to get rid of the \'es.
  245.  * Moreover, as we want to make use of the new FAST search
  246.  * routine, we have to remove the pattern anchoring (^ and $)
  247.  * and search direction characters (? or /)
  248.  */
  249.  
  250. alterpattern(pattern)
  251. register char pattern[];
  252. {
  253.     register int    i   = 0;        /* EMACS pattern index    */
  254.     register int    j   = 1;        /* VI pattern -skip /or?*/
  255.     int        len = strlen(pattern)-1;/* pattern length - 1    */
  256.                         /* i.e. drop '/' or '?'    */
  257.  
  258.     if (pattern[len-1] == '$')  len--;
  259.  
  260.     while (++j < len)
  261.         if (pattern[j] != '\\')
  262.             pattern[i++] = pattern[j];
  263.         else if (pattern[j+1] == '\\')
  264.             pattern[i++] = pattern[++j];
  265.  
  266.     pattern[min(i, NPAT/2)] = '\0';    /* Terminate pattern string    */
  267.     return(TRUE);
  268. }
  269.  
  270.  
  271. /*
  272.  * Some locally shared variables
  273.  */
  274.  
  275. static int thisfile  = FALSE;        /* TRUE if curtp->t_fname equals*/
  276.                     /* curbp->fname when tagging    */
  277. static int tagvalid  = FALSE;        /* TRUE if last tag was a succes*/
  278.  
  279.  
  280. /*
  281.  * Tag current word if '.' is within a word, otherwise tag next word.
  282.  * '.' is preserved, and return information (= current filename) is saved.
  283.  */
  284. extern int PASCAL NEAR tagword(f, n)
  285.  
  286. int f, n;
  287.  
  288. {
  289.     LINE    *pretagdotp = curwp->w_dotp;    /* Preserve '.' info    */
  290.     int    pretagdoto  = curwp->w_doto;
  291.     int    i;
  292.  
  293.     if (restflag == TRUE)    /* Don't allow when in restricted mode    */
  294.         return(resterr());
  295.  
  296.     if (lookup() == FALSE) { /* Is 'tags' avaliable for this file?    */
  297.         mlwrite("[Sorry, can't find any 'tags']");
  298.         return(FALSE);
  299.     }
  300.  
  301.     /* Get word to tag    */
  302.     if (inword()) {
  303.         backupword(FALSE, 1);
  304.         restword(curtp->t_wd, TAGWIDTH);    /* Grab word to tag    */
  305.     }
  306.     else if (mlreply("Word to tag: ", curtp->t_wd, TAGWIDTH) != TRUE)
  307.         return(FALSE);
  308.  
  309.     fix_index();
  310.  
  311.     curwp->w_dotp = pretagdotp;    /* Restore '.'    */
  312.     curwp->w_doto = pretagdoto;
  313.  
  314.     /* Ok, set file offset according to  curtp->t_wd (if any)    */
  315.     if ((i=INDEX(*curtp->t_wd)) == -1  ||  curtp->t_dotos[i] == -1L) {
  316.         mlwrite("[No tag entry for '%s' found]", curtp->t_wd);
  317.         return(FALSE);
  318.     }
  319.     fseek(curtp->t_fp, curtp->t_dotos[i], 0);
  320.  
  321.     strcpy(curtp->t_fname, curbp->b_fname); /* Save name of current file */
  322.     return(tagvalid = tagger("[No tag entry for '%s' found]", FALSE));
  323. }
  324.  
  325.  
  326. /*
  327.  * Does the actual work.  Presumes that  tagw  containes the correct
  328.  * word to tag.  Note that we do not rewind the file pointer as to
  329.  * allow you to do a re-tag.
  330.  * If the tagged word is defined in the current file we mark '.', 
  331.  * goes to line 1 of file and searches for the pattern.  We do this
  332.  * so as to prevent loosing the return information.
  333.  */
  334.  
  335. tagger(errmsg, retag)
  336. char *errmsg;
  337. int  retag;
  338. {
  339.     char    tagf[NFILEN];            /* File of tagged word    */
  340.     char    pretagpat[NPAT];        /* Search pattern prior    */
  341.                         /* to our tagging.    */
  342.     char    line[NLINE];            /* Auxilliary string    */
  343.     int    ok = 1;                /* Tag search flag    */
  344.     int    result   = FALSE;        /* Default return value */
  345.     int    oldbmode;            /* For preserving bmode    */
  346.     int    taglen   = strlen(curtp->t_wd);
  347.     int    file_ok;            /* TRUE if file found    */
  348.  
  349.     /* Tell user what we are doing        */
  350.     mlwrite("[Tagging '%s'...]", curtp->t_wd);
  351.  
  352.     /* Search for  curtp->t_wd  in the 'tags' file    */
  353.     while (ok > 0  &&  fgets(line, NLINE, curtp->t_fp) != NULL) {
  354.         if ((ok = strncmp(curtp->t_wd, line, taglen)) < 0)
  355.             break;
  356.         else if (ok == 0  &&  line[taglen] != '\t')
  357.             ok = -1;
  358.     }
  359.  
  360.     if (ok < 0) {                /* We couldn't find it..*/
  361.         mlwrite(errmsg, curtp->t_wd);
  362.         return(FALSE);
  363.     }
  364.  
  365.     strcpy(pretagpat, pat);        /* Preserve old search pattern    */
  366.  
  367.     /* Scan line for file and pattern    */
  368.     sscanf(line, "%s %s %[^\n]", curtp->t_wd, tagf, pat);
  369.     /* Alter pattern... we cannot use vi's    */
  370.     alterpattern(pat);
  371.  
  372.     /* Add path to tagf if necessary...    */
  373.     add_path(tagf);
  374.     /* Should we search the current file?    */
  375.     thisfile = strcmp(tagf, curbp->b_fname) == 0;
  376.     file_ok  = thisfile ? TRUE : getfile(tagf, TRUE);
  377.     oldbmode = curbp->b_mode;    /* Preserve buffer mode        */
  378.     if (file_ok) {            /* Ok, we got the file. Search!    */
  379.         if (thisfile  &&  retag == FALSE)
  380.             /* It's the same file so just set mark    */
  381.             setmark(FALSE, FALSE);
  382.         gotoline(TRUE, 1);
  383.  
  384.         /* Set-up for searching... use exact mode, not magic    */
  385.         curbp->b_mode |= MDEXACT;
  386.         curbp->b_mode &= ~MDMAGIC;
  387.         setjtable();
  388.         mcclear();
  389.         rmcclear();
  390.  
  391.         if (scanner(FORWARD, PTBEG, 1) == FALSE) {
  392.             /* Sorry, we couldn't find pattern so return...    */
  393.             if (thisfile  &&  retag == FALSE)
  394.                 /* It's the same file so simply swapmark*/
  395.                 swapmark(FALSE, FALSE);
  396.             else    /* Get old file    */
  397.                 getfile(curtp->t_fname, TRUE);
  398.             /* Tell user about our misfortune    */
  399.             mlwrite("[Failed to tag '%s']", curtp->t_wd);
  400.         }
  401.         else {    /* We found the pattern.  Now point at word!    */
  402.             strcpy(pat, curtp->t_wd);
  403.             setjtable();
  404.             result = scanner(FORWARD, PTBEG, 1);
  405.         }
  406.     }
  407.  
  408.     curbp->b_mode = oldbmode;    /* Restore buffer mode        */
  409.  
  410.     strcpy(pat, pretagpat);        /* Restore search pattern    */
  411.     setjtable();
  412.     if (curbp->b_mode & MDMAGIC)
  413.         mcstr();
  414.     else {
  415.         mcclear();
  416.         rmcclear();
  417.     }
  418.  
  419.     return(result);
  420. }
  421.  
  422.  
  423. /*
  424.  * Prefix filename with path in curtp->t_path (if any)
  425.  * if filename doesn't include a full path.  This routine
  426.  * allways succeeds.
  427.  */
  428.  
  429. add_path(filename)
  430. char *filename;
  431. {
  432.     char temp[NFILEN];
  433.     char *tp;
  434.  
  435.     if (strcmp(curtp->t_path, CURDIR) == 0)
  436.         return;
  437.  
  438. #if RISCOS
  439.     for (tp = filename; *tp && *tp != DIRSEPCHAR && *tp != ':'; tp++)
  440.         ;
  441.  
  442.     if (*tp == DIRSEPCHAR && tp == filename + 1)
  443.     {
  444.         switch (upperc(*tp))
  445.         {
  446.         case 'C':
  447.         case 'H':
  448.         case 'L':
  449.         case 'Y':
  450.             break;
  451.         default:
  452.             return;
  453.         }
  454.     }
  455.     else if (*tp == DIRSEPCHAR || *tp == ':')
  456.         return;
  457. #else
  458. #if MSDOS
  459.     for (tp = filename; *tp && *tp != DIRSEPCHAR && *tp != ':'; tp++)
  460.         ;
  461.  
  462.     if (*tp == DIRSEPCHAR || *tp == ':')
  463.         return;
  464. #else
  465.     for (tp = filename; *tp && *tp != DIRSEPCHAR; tp++)
  466.         ;
  467.  
  468.     if (*tp == DIRSEPCHAR)
  469.         return;
  470. #endif
  471. #endif
  472.  
  473.     strcpy(temp, curtp->t_path);
  474.     strcat(temp, filename);
  475.     strcpy(filename, temp);
  476. }
  477.  
  478.  
  479.  
  480. /*
  481.  * Sometimes the 'tags' file will contain multiple entries for the
  482.  * same identifier.  This occures whenever an identifier is multiple
  483.  * defined.  retagword  asks  tagger  to tag for the same  tagw  again
  484.  * but after the position where the last tag entry for tagw was found.
  485.  * Note, retagword  do not mess up the return information (tagf).
  486.  */
  487.  
  488. extern int PASCAL NEAR retagword(f, n)
  489.  
  490. int f, n;
  491.  
  492. {
  493.     if (restflag == TRUE)    /* Don't allow when in restricted mode    */
  494.         return(resterr());
  495.  
  496.     if (*curtp->t_fname == '\0'  ||  !tagvalid)
  497.         return(FALSE);
  498.  
  499.     return(tagger("[No additional tag entry for '%s' found]", TRUE));
  500. }
  501.  
  502.  
  503. /*
  504.  * Return to the file from where we tagged the  tagw  identifier.
  505.  * You can only return once for each tag.  If it's the same file
  506.  * we just swap mark with '.' .
  507.  */
  508.  
  509. extern int PASCAL NEAR backtagword(f, n)
  510.  
  511. int f, n;
  512.  
  513. {
  514.     if (restflag == TRUE)    /* Don't allow when in restricted mode    */
  515.         return(resterr());
  516.  
  517.     if (*curtp->t_fname != '\0') {
  518.         if (thisfile)
  519.             swapmark(FALSE, FALSE);
  520.         else
  521.             getfile(curtp->t_fname, TRUE);
  522.         *curtp->t_fname = '\0';
  523.     }
  524.  
  525.     return(TRUE);
  526. }
  527. #else
  528. tagshello()
  529. {
  530. }    
  531. #endif
  532.